/** @file nim_cpp_global.cpp
 * @brief NIM SDK提供的一些全局接口
 * @copyright (c) 2015-2017, NetEase Inc. All rights reserved
 * @date 2015/2/1
 */

#include "nim_cpp_wrapper/api/nim_cpp_global.h"
#include "nim_client_def.h"
#include "nim_cpp_wrapper/helper/nim_sdk_loader_helper.h"

namespace nim {
#ifdef NIM_SDK_DLL_IMPORT
typedef void (*nim_global_free_str_buf)(char* str);
typedef void (*nim_global_free_buf)(void* data);
typedef void (*nim_global_set_proxy)(NIMProxyType, const char*, int, const char*, const char*);
typedef void (*nim_global_detect_proxy)(enum NIMProxyType type,
    const char* host,
    int port,
    const char* user,
    const char* password,
    nim_global_detect_proxy_cb_func cb,
    const void* user_data);
typedef void (*nim_global_reg_exception_report_cb)(const char* json_extension, nim_sdk_exception_cb_func cb, const void* user_data);
typedef void (*nim_global_get_sdk_cache_file_info_async)(const char* login_id,
    const char* file_type,
    int64_t end_timestamp,
    const char* json_extension,
    nim_sdk_get_cache_file_info_cb_func cb,
    const void* user_data);
typedef void (*nim_global_del_sdk_cache_file_async)(const char* login_id,
    const char* file_type,
    int64_t end_timestamp,
    const char* json_extension,
    nim_sdk_del_cache_file_cb_func cb,
    const void* user_data);
typedef void (*nim_global_sdk_feedback_async)(const char* url, const char* json_extension, nim_sdk_feedback_cb_func cb, const void* user_data);
typedef void (*nim_global_reg_sdk_db_error_cb)(nim_global_sdk_db_error_cb_func cb, const void* user_data);
typedef void (*nim_global_upload_sdk_log)(const char* feedback_message, nim_global_upload_sdk_log_cb_func cb, const void* user_data);
#else
#include "nim_global.h"
#endif

void Global::FreeStrBuf(char* str) {
    NIM_SDK_GET_FUNC(nim_global_free_str_buf)(str);
}

void Global::FreeBuf(void* data) {
    NIM_SDK_GET_FUNC(nim_global_free_buf)(data);
}

void Global::SetProxy(NIMProxyType type, const std::string& host, int port, const std::string& user, const std::string& password) {
    NIM_SDK_GET_FUNC(nim_global_set_proxy)(type, host.c_str(), port, user.c_str(), password.c_str());
}

static void CallbackDetectProxy(bool connect, NIMProxyDetectStep step, const char* json_extension, const void* user_data) {
    CallbackProxy::DoSafeCallback<Global::DetectProxyCallback>(
        user_data,
        [=](const Global::DetectProxyCallback& cb) {
            CallbackProxy::Invoke(cb, connect, step, PCharToString(json_extension));
        },
        true);
}

void Global::DetectProxy(NIMProxyType type,
    const std::string& host,
    int port,
    const std::string& user,
    const std::string& password,
    const Global::DetectProxyCallback& callback) {
    Global::DetectProxyCallback* cb_pointer = nullptr;
    if (callback) {
        cb_pointer = new Global::DetectProxyCallback(callback);
    }
    NIM_SDK_GET_FUNC(nim_global_detect_proxy)(type, host.c_str(), port, user.c_str(), password.c_str(), &CallbackDetectProxy, cb_pointer);
}

static void CallbackException(NIMSDKException exception, const char* log, const void* user_data) {
    CallbackProxy::DoSafeCallback<Global::ExceptionCallback>(user_data, [=](const Global::ExceptionCallback& cb) {
        std::string a;
        a.append(log);
        CallbackProxy::Invoke(cb, exception, a);
    });
}

void Global::SetExceptionReportCallback(const std::string& json_extension, const ExceptionCallback& cb) {
    ExceptionCallback* cb_pointer = nullptr;
    if (cb) {
        cb_pointer = new ExceptionCallback(cb);
    }
    NIM_SDK_GET_FUNC(nim_global_reg_exception_report_cb)(json_extension.c_str(), &CallbackException, cb_pointer);
}

static void CallbackGetCachedFileInfo(const char* info, const void* user_data) {
    CallbackProxy::DoSafeCallback<Global::GetCachedFileInfoCallback>(
        user_data,
        [=](const Global::GetCachedFileInfoCallback& cb) {
            Global::CachedFileInfo out;
            nim_cpp_wrapper_util::Json::Value values;
            if (nim::ParseJsonValue(PCharToString(info), values) && values.isObject()) {
                out.file_type_ = values[kNIMCacheFileType].asString();
                out.file_path_ = values[kNIMCacheFilePath].asString();
                out.file_count_ = values[kNIMCacheFileCount].asInt();
                out.file_total_size_ = values[kNIMCacheFileTotalSize].asUInt64();
                CallbackProxy::Invoke(cb, kNIMResSuccess, out);
            }
        },
        true);
}

static void CallbackDeleteCachedFile(enum NIMResCode code, const void* user_data) {
    CallbackProxy::DoSafeCallback<Global::DeleteCachedFileCallback>(user_data, [=](const Global::DeleteCachedFileCallback& cb) {
        CallbackProxy::Invoke(cb, code);
    });
}

void Global::GetSDKCachedFileInfoAsync(const std::string& login_id,
    const std::string& file_type,
    int64_t end_timestamp,
    const std::string& json_extension,
    const GetCachedFileInfoCallback& cb) {
    GetCachedFileInfoCallback* cb_pointer = nullptr;
    if (cb) {
        cb_pointer = new GetCachedFileInfoCallback(cb);
    }
    NIM_SDK_GET_FUNC(nim_global_get_sdk_cache_file_info_async)
    (login_id.c_str(), file_type.c_str(), end_timestamp, json_extension.c_str(), &CallbackGetCachedFileInfo, cb_pointer);
}

void Global::DeleteSDKCachedFileAsync(const std::string& login_id,
    const std::string& file_type,
    int64_t end_timestamp,
    const std::string& json_extension,
    const DeleteCachedFileCallback& cb) {
    DeleteCachedFileCallback* cb_pointer = nullptr;
    if (cb) {
        cb_pointer = new DeleteCachedFileCallback(cb);
    }
    NIM_SDK_GET_FUNC(nim_global_del_sdk_cache_file_async)
    (login_id.c_str(), file_type.c_str(), end_timestamp, json_extension.c_str(), &CallbackDeleteCachedFile, cb_pointer);
}

static void CallbackSDKFeedback(enum NIMResCode code, const void* user_data) {
    CallbackProxy::DoSafeCallback<Global::SDKFeedbackCallback>(user_data, [=](const Global::SDKFeedbackCallback& cb) {
        CallbackProxy::Invoke(cb, code);
    });
}

void Global::SDKFeedbackAsync(const std::string& url, const std::string& json_extension, const SDKFeedbackCallback& cb) {
    SDKFeedbackCallback* cb_pointer = nullptr;
    if (cb) {
        cb_pointer = new SDKFeedbackCallback(cb);
    }
    NIM_SDK_GET_FUNC(nim_global_sdk_feedback_async)(url.c_str(), json_extension.c_str(), &CallbackSDKFeedback, cb_pointer);
}
Global::SDKDBErrorCallback g_sdkdberror = nullptr;
void Global::RegSDKDBError(const Global::SDKDBErrorCallback& cb) {
    if (cb != nullptr)
        g_sdkdberror = cb;
    NIM_SDK_GET_FUNC(nim_global_reg_sdk_db_error_cb)
    (
        [](const char* error_info, const void* user_data) {
            CallbackProxy::DoSafeCallback<Global::SDKDBErrorCallback>(user_data, [=](const Global::SDKDBErrorCallback& cb) {
                SDKDBErrorInfo error;
                nim_cpp_wrapper_util::Json::Value json_error;
                if (nim::ParseJsonValue(error_info, json_error)) {
                    error.db_name_ = json_error[kNIMDBErrDBName].asString();
                    error.attach_ = json_error[kNIMDBErrAttach].asString();
                    error.description_ = json_error[kNIMDBErrDescription_].asString();
                    error.operation_ = json_error[kNIMDBERROperation].asInt();
                    error.error_code_ = json_error[kNIMDBErrCode].asInt();
                }
                CallbackProxy::Invoke(cb, error);
            });
        },
        &g_sdkdberror);
}
void Global::UploadSDKLog(const std::string& feedback_message, const SDKFeedbackCallback& cb) {
    SDKFeedbackCallback* callback = nullptr;
    if (cb != nullptr) {
        callback = new SDKFeedbackCallback(cb);
    }
    NIM_SDK_GET_FUNC(nim_global_upload_sdk_log)
    (
        feedback_message.c_str(),
        [](int rescode, const void* callback) {
            CallbackProxy::DoSafeCallback<SDKFeedbackCallback>(
                callback,
                [=](const SDKFeedbackCallback& cb) {
                    CallbackProxy::Invoke(cb, (NIMResCode)rescode);
                },
                true);
        },
        callback);
}
}  // namespace nim
